package com.bzkj.document.service.otherinboundorder.impl;

import com.alibaba.fastjson2.JSONObject;
import com.bzkj.common.annotation.DataWarehouseScope;
import com.bzkj.common.constant.BillStatusConstant;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.domain.model.LoginUser;
import com.bzkj.common.core.page.TableDataInfo;
import com.bzkj.common.domain.NccApiResponse;
import com.bzkj.common.domain.NccRequestDTO;
import com.bzkj.common.enums.BusinessType;
import com.bzkj.common.enums.DocumentType;
import com.bzkj.common.exception.InformationTipException;
import com.bzkj.common.utils.DataProcessCommonUtils;
import com.bzkj.common.utils.MessageUtil;
import com.bzkj.common.utils.http.NccHttpUtils;
import com.bzkj.document.domain.DocConfirmDTO;
import com.bzkj.document.domain.otherinorder.dto.ICGeneralInB;
import com.bzkj.document.domain.otherinorder.dto.ICGeneralInH;
import com.bzkj.document.domain.otherinorder.dto.ICGeneralInRequest;
import com.bzkj.document.domain.otherinorder.dto.OtherInboundQueryDTO;
import com.bzkj.document.domain.otherinorder.vo.OtherInBoundBodyVo;
import com.bzkj.document.domain.otherinorder.vo.OtherInBoundHeaderVo;
import com.bzkj.document.enums.InventoryCheck;
import com.bzkj.document.enums.ProcessingType;
import com.bzkj.document.exception.InventoryException;
import com.bzkj.document.mapper.OtherInboundOrderMapper;
import com.bzkj.document.mapper.WmsWareHouseInventoryMapper;
import com.bzkj.document.service.otherinboundorder.OtherInboundOrderService;
import com.bzkj.document.utils.common.DataProcessUtils;
import com.bzkj.document.utils.common.DocumentNoUtils;
import com.bzkj.document.utils.common.InventoryManagerUtils;
import com.bzkj.document.utils.otherinbound.OtherInboundUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @projectName: bzkj-wms
 * @package: com.bzkj.document.service.otherinboundorder.impl
 * @className: OtherInboundOrderServiceImpl
 * @description: 其他入库单业务层实现类
 * @author: C1309
 * @createDate: 2024年11月26日
 * @version: v1.0
 */
@Service
public class OtherInboundOrderServiceImpl implements OtherInboundOrderService {

    /**
     * 其他入库单持久层
     */
    @Resource
    private OtherInboundOrderMapper otherInboundOrderMapper;

    @Resource
    private WmsWareHouseInventoryMapper wmsWareHouseInventoryMapper;

    /**
     * 生成WMS单据号
     */
    @Resource
    private DocumentNoUtils documentNoUtils;

    /**
     * 库存管理工具
     */
    @Resource
    private InventoryManagerUtils inventoryManagerUtils;

    /**
     * 消息提示工具
     */
    @Resource
    private MessageUtil messageUtil;

    /**
     * 其他入库单处理工具
     */
    @Resource
    private OtherInboundUtils otherInboundUtils;

    private static final String QUERY_API_URL = "/nccloud/api/ic/generalin/schemequery";

    private static final String ADD_API_URL = "/nccloud/api/ic/generalin/save";

    private static final String DELETE_API_URL = "/nccloud/api/ic/generalin/delete";

    private static final String AUDIT_API_URL = "/nccloud/api/ic/generalin/sign";

    private static final String UPDATE_API_URL = "/nccloud/api/ic/generalin/update";

    /**
     * NCC接口请求工具
     */
    @Resource
    private NccHttpUtils nccHttpUtils;

    // ==========================================================
    // 模块名称: 其他入库单NCC查询模块
    // 功能描述: 对NCC其他入库单进行查询操作
    // ==========================================================

    /**
     * 查询NCC其他入库单
     *
     * @param nccRequestDTO 查询条件
     * @return 查询结果
     */
    @Override
    public TableDataInfo selectNccOtherInboundOrder(NccRequestDTO nccRequestDTO) {
        try {
            nccHttpUtils.setWarehouseId(nccRequestDTO, wmsWareHouseInventoryMapper.selectWarehouseId());
            // 发起请求并处理响应
            NccApiResponse nccApiResponse = nccHttpUtils.post(QUERY_API_URL, JSONObject.toJSONString(nccRequestDTO));
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            // 解析NCC返回的其他入库单数据
            List<Map<String, Object>> dataList = otherInboundUtils.parsingOtherInboundOrders(nccApiResponse, ProcessingType.SELECT_NCC_ORDER.ordinal(), true);

//            if (dataList == null || dataList.isEmpty()) {
//                throw new RuntimeException("Oops~ 当前条件下没有找到单据，试试调整查询条件吧！");
//            }
            // 返回分页数据
            return DataProcessUtils.startPageInfo(nccRequestDTO.getPageNum(), nccRequestDTO.getPageSize(), dataList);
        } catch (Exception e) {
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.OTHER_INBOUND.getCode(), e, "查询");
            throw new RuntimeException(errorMessage, e);
        }
    }

    // ==========================================================
    // 模块名称: wms确认ncc其他入库单模块
    // 功能描述: 对ncc其他入库单进行确认操作
    // ==========================================================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult confirmOtherInboundOrder(DocConfirmDTO docConfirmDTO) {
        // 提取登录用户信息
        LoginUser loginUser = docConfirmDTO.getLoginUser();
        // 提取单据日期范围信息
        String billDate = nccHttpUtils.getBillDate(docConfirmDTO.getBillDate());
        // 提取单据号信息
        List<String> billCodeList = docConfirmDTO.getvBillCodeList();
        int confirmType = docConfirmDTO.getConfirmType() == null ? 1 : docConfirmDTO.getConfirmType();
        List<String> errorList = new ArrayList<>();
        List<String> successList = new ArrayList<>();

        // 逐一处理单据
        for (String billCode : billCodeList) {
            try {
                // 检查单据是否已存在
                if (isBillExist(billCode)) {
//                    log.warn("单据 {} 已存在，跳过处理。", billCode);
                    continue;
                }

                // 从 NCC 获取单据数据
                List<Map<String, Object>> otherInOrders = fetchOtherInboundOrders(billCode, billDate);

                // 处理单据
                String errorMsg = processOtherInboundOrder(otherInOrders, loginUser, successList, billCode, confirmType);

                if (errorMsg != null) {
                    String[] split = errorMsg.split("x-x");
                    if (split.length == 2) {
                        if ("1".equals(split[0])) {
                            throw new RuntimeException(split[1]);
                        } else if ("2".equals(split[0])) {
                            return AjaxResult.wmsApiWarning(split[1]);
                        }
                    }
                }
            } catch (Exception e) {
//                log.error("单据 {} 处理失败：{}", billCode, e.getMessage(), e);
                throw new RuntimeException(messageUtil.operateExceptionMessage(DocumentType.OTHER_INBOUND.getCode(), e, "确认"), e);
            }
        }

        // 构造返回结果
        if (!errorList.isEmpty()) {
            String errorMessage = String.join("\n", errorList);
            return AjaxResult.warn("错误信息：<br>" + errorMessage);
        }
        return AjaxResult.success(messageUtil.operateSuccessMessage(billCodeList, DocumentType.OTHER_INBOUND.getCode(), "确认"));
    }

    /**
     * 检查单据是否已存在
     */
    private boolean isBillExist(String billCode) {
        return otherInboundOrderMapper.selectIsExist(billCode) > 0;
    }

    /**
     * 调用 NCC 接口获取物料出库单数据
     */
    private List<Map<String, Object>> fetchOtherInboundOrders(String billCode, String billDate) throws Exception {

        String getConfirmQuery = nccHttpUtils.getConfirmQuery(billDate, billCode);
        // 发起请求并处理响应
        NccApiResponse nccApiResponse = nccHttpUtils.post(QUERY_API_URL, getConfirmQuery);
        DataProcessCommonUtils.validateNccResponse(nccApiResponse);
        return otherInboundUtils.parsingOtherInboundOrders(nccApiResponse, ProcessingType.CONFIRM_ORDER.ordinal(), true);
    }

    /**
     * 处理单据数据
     */
    @Transactional(rollbackFor = Exception.class)
    public String processOtherInboundOrder(List<Map<String, Object>> otherInboundOrders, LoginUser loginUser, List<String> successList, String billCode, int confirmType) {
        try {
            for (Map<String, Object> otherInboundOrder : otherInboundOrders) {
                // 提取明细数据并校验
                List<Map<String, Object>> detailsList = inventoryManagerUtils.extractDetailsList(otherInboundOrder, loginUser);
                // 提取表头数据并插入
                Map<String, Object> headerMap = extractHeaderMap(otherInboundOrder, loginUser);
                String validationError = inventoryManagerUtils.checkErrorMsg(detailsList);
                if (validationError != null) {
                    return "1x-x" + validationError;
                }
                // 校验明细行出库批号是否为WMS最优出库批号
                String batchNoError = inventoryManagerUtils.checkBatchNo(detailsList, confirmType, "warehousein");
                if (batchNoError != null) {
                    return "2x-x" + batchNoError;
                }

                // 入库类型
                String vtrantypecode = headerMap.get("vtrantypecode").toString();

                // 校验WMS库存并插入明细数据
                int detailsResult = batchInsertDetails(detailsList, vtrantypecode);

                billCode = Optional.ofNullable(billCode).orElse((String) headerMap.get("vbillcode"));

                if (detailsResult == detailsList.size()) {
                    // 插入表头数据
                    int headerResult = otherInboundOrderMapper.addOtherInboundOrderHeader(headerMap);
                    if (headerResult > 0) {
                        // 向NCC返回同步状态
                        NccApiResponse nccApiResponse = nccHttpUtils.postNoSaleConfirm(UPDATE_API_URL, headerMap.get("cgeneralhid").toString(), "ic_generalin_h", "Y");
                        if (nccApiResponse.isSuccess()) {
                            // 记录成功单据
                            successList.add(billCode);
                        } else {
                            throw new RuntimeException("向NCC返回单据同步状态失败，请检查后重试！");
                        }
                    }

                }
            }
            return null;
        } catch (Exception e) {
//            log.error("单据 {} 处理过程中发生未知异常：{}", billCode, e.getMessage(), e);
            throw new InformationTipException("单据处理失败：" + e.getMessage(), e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public int batchInsertDetails(List<Map<String, Object>> detailsList, String vtrantypecode) {
        AtomicInteger count = new AtomicInteger();
        // 判断库存量是否充足
        boolean verifyInventory = inventoryManagerUtils.verifyInventoryConfirm(detailsList, "warehousein", vtrantypecode, DocumentType.OTHER_INBOUND.getCode());
        if (verifyInventory) {
            detailsList.forEach(detail -> {
                count.addAndGet(otherInboundOrderMapper.addOtherInboundOrderDetails(detail));
            });
        }
        return count.get();
    }

    private void processNegativeQuantityDetail(String vtrantypecode, Map<String, Object> detail) {
        @SuppressWarnings("unchecked") Map<String, Object> cmaterialvid = (Map<String, Object>) detail.get("cmaterialvid");
        String pkMaterial = Optional.ofNullable(cmaterialvid).map(c -> c.get("isMap") != null && (boolean) c.get("isMap") ? c.get("pk").toString() : c.get("value").toString()).orElseThrow(() -> new InformationTipException("物料信息缺失！"));

        String vbatchcode = Optional.ofNullable(detail.get("vbatchcode")).map(Object::toString).orElse("");
        double nshouldnum = Double.parseDouble(detail.get("nshouldnum").toString());
        String cstateid = Optional.ofNullable(detail.get("cstateid")).map(Object::toString).orElse("");

        int resultType = inventoryManagerUtils.isEnough("", vtrantypecode, pkMaterial, vbatchcode, nshouldnum, "1", cstateid, "", "");
        if (Objects.equals(resultType, InventoryCheck.ENOUGH)) {
            if (otherInboundOrderMapper.addOtherInboundOrderDetails(detail) <= 0) {
                throw new InformationTipException("单据明细数据同步失败！");
            }
        } else if (Objects.equals(resultType, "0")) {
            throw new InformationTipException(cmaterialvid.get("name") + "库存可用量不足！");
        } else if (Objects.equals(resultType, "2")) {
            throw new InformationTipException(cmaterialvid.get("name") + "当前商品不支持在此单据类型下使用！");
        }
    }

    /**
     * 提取表头数据
     */
    private Map<String, Object> extractHeaderMap(Map<String, Object> otherInboundOrder, LoginUser loginUser) {
        @SuppressWarnings("unchecked") Map<String, Object> headerMap = (Map<String, Object>) otherInboundOrder.get("header");
        String wmsOutNo = documentNoUtils.generateOitOrderNumber();
        headerMap.put("vdef49", wmsOutNo);
        headerMap.put("vdef50", wmsOutNo);
        DataProcessUtils.addHeaderInfo(headerMap, loginUser);
        return headerMap;
    }

    /**
     * 提取明细数据
     */
    private List<Map<String, Object>> extractDetailsList(Map<String, Object> otherInboundOrder, LoginUser loginUser) {
        @SuppressWarnings("unchecked") List<Map<String, Object>> detailsList = (List<Map<String, Object>>) otherInboundOrder.get("details");
        for (Map<String, Object> detail : detailsList) {
            DataProcessUtils.addDetailInfo(detail, loginUser);
        }
        return detailsList;
    }


    // ==========================================================
    // 模块名称: 新增ncc其他入库单模块
    // 功能描述: 对ncc其他入库单进行新增操作
    // ==========================================================

    /**
     * 新增NCC其他入库单
     *
     * @param responseBody 请求参数
     * @return 操作结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult addOtherInboundOrder(ICGeneralInRequest responseBody) {

        // 初始化成功处理列表
        List<String> successList = new ArrayList<>();

        // 提取登录用户信息
        LoginUser loginUser = responseBody.getLoginUser();
        // 提取请求参数头信息
        ICGeneralInH icGeneralInH = responseBody.getIcGeneralInH();
        // 提取请求参数明细信息
        List<ICGeneralInB> icGeneralInBS = responseBody.getIcGeneralInB();
        // 检查头信息是否为空
        if (icGeneralInH == null) {
            return AjaxResult.warn("小提示：其他入库单据头信息缺失，请确认提交的请求格式是否正确！");
        }
        if (icGeneralInBS == null || icGeneralInBS.isEmpty()) {
            return AjaxResult.warn("小提示：其他入库单据明细数据缺失，请确认提交的请求格式是否正确！");
        }

        for (ICGeneralInB icGeneralInB : icGeneralInBS) {
            if (icGeneralInB.getnShouldNum() == 0) {
                return AjaxResult.warn("注意：提供的明细数据中应收主数量存在为0项，请核对后重试！");
            }
        }


        // 将请求对象转换为JSON格式
        String requestJson = JSONObject.toJSONString(responseBody);

        try {
            // 调用 NCC 接口并获取返回结果
            NccApiResponse nccApiResponse = nccHttpUtils.post(ADD_API_URL, "[" + requestJson + "]");

            // 校验 NCC 返回结果
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            // 解析返回数据
            List<Map<String, Object>> otherInboundOrders = otherInboundUtils.parsingOtherInboundOrders(nccApiResponse, icGeneralInBS, true);

            // 处理其他入库单数据
            processOtherInboundOrder(otherInboundOrders, loginUser, successList, null, 1);

        } catch (Exception e) {
            // 统一异常处理并抛出运行时异常
            String exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.OTHER_INBOUND.getCode(), e, "新增");
            throw new RuntimeException(exceptionMessage, e);
        }

        // 返回操作成功结果
        return AjaxResult.success(messageUtil.operateSuccessMessage(successList, DocumentType.OTHER_INBOUND.getCode(), "新增"));

    }


    // ==========================================================
    // 模块名称: 查询WMS其他入库单模块
    // 功能描述: 查询WMS其他入库单
    // ==========================================================

    /**
     * 查询本地其他入库单
     *
     * @param otherInboundQueryDTO 查询参数
     * @return 查询结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @DataWarehouseScope(deptAlias = "d", userAlias = "u")
    public TableDataInfo getLocalOtherInboundOrder(OtherInboundQueryDTO otherInboundQueryDTO, int pageNum, int pageSize) {
        // 处理日期范围过滤条件
        DataProcessUtils.handleDateRange(otherInboundQueryDTO);

        // 处理单据状态过滤条件
        String originalBillsState = Optional.ofNullable(otherInboundQueryDTO.getBillsState())
                .filter(state -> !state.isEmpty())
                .orElse(null);

        // For header query, we modify state 4/5 to 3
        String headerQueryBillsState = originalBillsState != null
                ? (originalBillsState.equals("4") || originalBillsState.equals("5") ? "3" : originalBillsState)
                : null;
        otherInboundQueryDTO.setBillsState(headerQueryBillsState);

        //查询表头数据
        List<OtherInBoundHeaderVo> localOtherInboundOrderList = otherInboundOrderMapper.getLocalOtherInBoundHeader(otherInboundQueryDTO);
        if (localOtherInboundOrderList.isEmpty()) {
            return DataProcessCommonUtils.getTableInfo(Collections.emptyList(), pageNum, pageSize);
        }

        // 获取物料过滤条件
        String filterMaterialOid = Optional.ofNullable(otherInboundQueryDTO.getMaterial()).orElse("");
        boolean shouldFilterByMaterial = !filterMaterialOid.isEmpty();
        boolean shouldFilterBySkuState = originalBillsState != null
                && (originalBillsState.equals("4") || originalBillsState.equals("5"));

        List<HashMap<String, Object>> responseDataList = localOtherInboundOrderList.parallelStream().map(otherInHeaderVo -> {
                    // 查询对应单据明细
                    List<OtherInBoundBodyVo> localOtherInboundOrderDetails = otherInboundOrderMapper.getLocalOtherInBoundDetails(otherInHeaderVo.getCgeneralhid(), otherInHeaderVo.getBillsState());
                    if (localOtherInboundOrderDetails == null || localOtherInboundOrderDetails.isEmpty()) {
                        return null;
                    }

                    // 如果存在物料过滤条件，先检查明细中是否包含该物料
                    if (shouldFilterByMaterial && localOtherInboundOrderDetails.stream()
                            .noneMatch(body -> filterMaterialOid.equals(body.getCmaterialoid().getPk()))) {
                        return null;

                    }
                    if (shouldFilterBySkuState && localOtherInboundOrderDetails.stream()
                            .noneMatch(body -> originalBillsState.equals(body.getSkuState()))) {
                        return null;
                    }
                    // 构建结果
                    HashMap<String, Object> result = new HashMap<>(2);
                    result.put("header", otherInHeaderVo);
                    result.put("details", localOtherInboundOrderDetails);
                    return result;
                }).filter(Objects::nonNull)
                .collect(Collectors.toList());

        return DataProcessCommonUtils.getTableInfo(responseDataList, pageNum, pageSize);
    }


    // ==========================================================
    // 模块名称: 更新WMS其他入库单模块
    // 功能描述: 更新WMS其他入库单
    // ==========================================================

    /**
     * 更新NCC其他入库单
     *
     * @param responseBody 请求参数
     * @param loginUser    登录用户
     * @param isSign       是否跳过校验
     * @return 操作结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult updateOtherInboundOrder(HashMap<String, Object> responseBody, LoginUser loginUser, boolean isSign) {
        String vbillcode;
        // 提取并校验头信息
        HashMap<String, Object> headerMap = extractHeaderInfo(responseBody);
        String cgeneralhid = headerMap.get("cgeneralhid").toString();

        // 校验单据状态
        if (!isSign) {
            AjaxResult validationResult = validateBillStatus(cgeneralhid);
            if (!validationResult.isSuccess()) {
                return validationResult;
            }
        }

        // 封装 NCC 请求参数
        HashMap<String, Object> nccRequestMap = prepareNccRequest(responseBody);
        JSONObject jsonObject = new JSONObject(nccRequestMap);
        JSONObject icGeneralinH = jsonObject.getJSONObject("ic_generalin_h");
        if (icGeneralinH.get("cwarehouseid")!=null){
            icGeneralinH.remove("cwarehouseid");
        }

        // 调用 NCC 接口并校验返回结果
        NccApiResponse nccApiResponse;
        try {
            nccApiResponse = nccHttpUtils.post(UPDATE_API_URL, jsonObject.toJSONString());

            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            // 解析和处理返回数据
            List<Map<String, Object>> otherInboundOrders = otherInboundUtils.parsingOtherInboundOrders(nccApiResponse, ProcessingType.UPDATE_NCC_ORDER.ordinal(), false);

            vbillcode = processOutboundOrders(otherInboundOrders, loginUser);

        } catch (Exception e) {
            String exceptionMessage;
            if (!isSign) {
                exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.OTHER_INBOUND.getCode(), e, "修改");
            } else {
                return AjaxResult.error(messageUtil.operateExceptionMessage(DocumentType.OTHER_INBOUND.getCode(), e, "签字"));
            }
            throw new RuntimeException(exceptionMessage, e);
        }
        // 返回成功结果
        return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillcode), DocumentType.OTHER_INBOUND.getCode(), "修改"));
    }

    /**
     * 提取头信息并校验
     */
    private HashMap<String, Object> extractHeaderInfo(HashMap<String, Object> responseBody) {
        @SuppressWarnings("unchecked") HashMap<String, Object> headerMap = (HashMap<String, Object>) responseBody.get("ic_generalin_h");
        if (headerMap == null || !headerMap.containsKey("cgeneralhid")) {
            throw new IllegalArgumentException("提示：单据头信息缺失或不完整！");
        }
        return headerMap;
    }

    /**
     * 校验单据状态
     */
    private AjaxResult validateBillStatus(String cgeneralhid) {
        HashMap<String, String> billInfoMap = otherInboundOrderMapper.getBillStatus(cgeneralhid);
        String billState = billInfoMap.get("billState");
        return messageUtil.updateBillMessage(billState, DocumentType.OTHER_INBOUND.getDescription());
    }

    /**
     * 封装 NCC 请求参数
     */
    private HashMap<String, Object> prepareNccRequest(HashMap<String, Object> responseBody) {
        HashMap<String, Object> nccRequestMap = new HashMap<>(2);
        nccRequestMap.put("ic_generalin_h", responseBody.get("ic_generalin_h"));
        nccRequestMap.put("ic_generalin_b", responseBody.get("ic_generalin_b"));
        return nccRequestMap;
    }

    /**
     * 处理其他入库单
     */
    private String processOutboundOrders(List<Map<String, Object>> otherInboundOrders, LoginUser loginUser) {
        String vbillcode = "";
        for (Map<String, Object> otherInboundOrder : otherInboundOrders) {
            @SuppressWarnings("unchecked") Map<String, Object> headerInfoMap = (Map<String, Object>) otherInboundOrder.get("header");
            vbillcode = headerInfoMap.get("vbillcode").toString();
            DataProcessUtils.updateInfo(headerInfoMap, loginUser);

            // 修改表头数据
            int resultNum = otherInboundOrderMapper.updateOtherInboundOrder(headerInfoMap);
            if (resultNum <= 0) {
                throw new RuntimeException("表头数据更新失败！");
            }

            // 修改表体数据
            @SuppressWarnings("unchecked") List<HashMap<String, Object>> detailsList = (List<HashMap<String, Object>>) otherInboundOrder.get("details");
            int count = updateOrderDetails(detailsList, loginUser);
            if (count != detailsList.size()) {
                String failureMessage = messageUtil.documentFailureMessage(Collections.singletonList(headerInfoMap.get("vbillcode").toString()), DocumentType.OTHER_INBOUND.getCode(), "修改", "明细");
                throw new RuntimeException(failureMessage);
            }
        }
        return vbillcode;
    }

    /**
     * 更新表体数据
     */
    private int updateOrderDetails(List<HashMap<String, Object>> detailsList, LoginUser loginUser) {
        int count = 0;
        for (HashMap<String, Object> detailMap : detailsList) {
            DataProcessUtils.updateInfo(detailMap, loginUser);
            count += otherInboundOrderMapper.updateOtherInboundOrderDetails(detailMap);
        }
        return count;
    }

    // ==========================================================
    // 模块名称: NCC其他出库单删除模块
    // 功能描述: 对NCC其他出库单进行删除操作
    // ==========================================================

    /**
     * 对NCC其他入库单进行删除
     *
     * @param header    表头主键
     * @param loginUser 登录用户
     * @param reason    删除原因
     * @return 操作结果
     */
    @Override
    public AjaxResult deleteOtherInboundOrder(String header, LoginUser loginUser, String reason) {

        if (header == null) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.OTHER_INBOUND.getCode(), BusinessType.INVALID.getDescription()));
        } else if (header.trim().isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.OTHER_INBOUND.getCode(), BusinessType.INVALID.getDescription()));
        }

        // 获取当前单据状态
        HashMap<String, String> billStatusMap = otherInboundOrderMapper.getBillStatus(header);
        String billState = billStatusMap.get("billState");
        String vbillcode = billStatusMap.get("vbillcode");

        // 校验单据状态
        AjaxResult ajaxResult = messageUtil.deleteBillMessage(billState, DocumentType.OTHER_INBOUND.getDescription());
        return ajaxResult.isSuccess() ? handleDeleteBill(header, vbillcode, loginUser, reason) : ajaxResult;

    }


    /**
     * 其他入库单删除
     *
     * @param cgeneralhid 表头主键
     * @param loginUser   登录用户
     * @param vBillcode   单据编号
     * @param reason      删除原因
     * @return 结果
     */
    private AjaxResult handleDeleteBill(String cgeneralhid, String vBillcode, LoginUser loginUser, String reason) {
        try {
            // 调用删除接口
            NccApiResponse nccApiResponse = nccHttpUtils.postNoSaleConfirm(UPDATE_API_URL, cgeneralhid, "ic_generalin_h", "");

            // 校验NCC响应
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            otherInboundOrderMapper.updateBillState(cgeneralhid, BillStatusConstant.DELETED_CODE, loginUser.getUsername(), null, reason);

            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vBillcode), DocumentType.OTHER_INBOUND.getCode(), BusinessType.INVALID.getDescription()));
        } catch (Exception e) {
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.OTHER_INBOUND.getCode(), e, BusinessType.INVALID.getDescription());
            //            log.error("采购入库单修改异常: ", e);
            throw new RuntimeException(errorMessage, e);
        }
    }

    // ==========================================================
    // 模块名称: NCC其他入库单签字模块
    // 功能描述: 对NCC其他入库单进行签字操作
    // ==========================================================

    /**
     * 对NCC其他入库单进行签字
     *
     * @param cgeneralhid 表体主键
     * @param loginUser   登录用户
     * @return 操作结果
     */
    @Override
    public AjaxResult otherInboundOrderSignature(String cgeneralhid, LoginUser loginUser) {
        // 参数校验：请求参数是否为空，headerId是否存在
        if (cgeneralhid == null || cgeneralhid.isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.OTHER_INBOUND.getCode(), "签字"));
        }

        // 获取当前单据状态
        HashMap<String, String> billStatusMap = otherInboundOrderMapper.getBillStatus(cgeneralhid);
        String billState = billStatusMap.get("billState");
        String vbillcode = billStatusMap.get("vbillcode");

        // 校验单据状态
        AjaxResult ajaxResult = messageUtil.signedBillMessage(billState, DocumentType.OTHER_INBOUND.getDescription());
        return ajaxResult.isSuccess() ? processSignBill(cgeneralhid, vbillcode, loginUser) : ajaxResult;
    }

    /**
     * 对已完成的单据进行签字处理
     *
     * @param cgeneralhid 表体主键
     * @param loginUser   登录用户
     * @param vBillCode   单据编号
     * @return 操作结果
     */

    private AjaxResult processSignBill(String cgeneralhid, String vBillCode, LoginUser loginUser) {
        try {
            // 准备表头数据
            HashMap<String, Object> headerMap = prepareHeaderData(cgeneralhid);
            String vtrantypecode = headerMap.get("vtrantypecode").toString();
            // 校验并准备明细数据
            List<HashMap<String, Object>> detailList = prepareDetails(cgeneralhid, vtrantypecode);
            if (detailList.isEmpty()) {
                return AjaxResult.error(messageUtil.updateDocumentZeroQuantityMessage(DocumentType.OTHER_INBOUND.getCode()));
            }

            // 更新其他入库单
            AjaxResult updateResult = updateOtherInOrder(headerMap, detailList, loginUser);
            if (!updateResult.isSuccess()) {
                return updateResult;
            }

            // 调用外部接口并更新状态
            return handleExternalApiAndInventory(cgeneralhid, vBillCode, loginUser, detailList.size());
        } catch (Exception e) {
            //            logError("采购入库单签字异常", e); // 记录异常日志
            String exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.OTHER_INBOUND.getCode(), e, "签字");
            throw new RuntimeException(exceptionMessage, e);
        }
    }

    /**
     * 校验并准备明细数据
     *
     * @param cgeneralhid 单据编号
     * @return 明细列表或null（校验失败）
     */
    private List<HashMap<String, Object>> prepareDetails(String cgeneralhid, String vtrantypecode) {
        // 查询单据明细信息
        List<OtherInBoundBodyVo> details = otherInboundOrderMapper.getLocalOtherInBoundDetails(cgeneralhid, null);
        // 构建更新明细列表
        List<HashMap<String, Object>> detailList = new ArrayList<>();
        // 校验库存是否充足
        boolean verifyInventory = inventoryManagerUtils.verifyInventorySign(details, "warehousein", vtrantypecode, DocumentType.OTHER_INBOUND.getCode());
        if (verifyInventory) {
            for (OtherInBoundBodyVo detail : details) {
                HashMap<String, Object> detailMap = new HashMap<>();
                detailMap.put("cgeneralbid", detail.getCgeneralbid());
                detailMap.put("nnum", detail.getNnum());
                detailList.add(detailMap);
            }
        }
        return detailList;
    }

    /**
     * 准备表头数据
     *
     * @param cgeneralhid 单据编号
     * @return 表头数据
     */
    private HashMap<String, Object> prepareHeaderData(String cgeneralhid) {
        OtherInBoundHeaderVo otherInBoundHeaderVo = otherInboundOrderMapper.selectOtherInboundOrderHeaderByBillCode(cgeneralhid);
        if (otherInBoundHeaderVo == null) {
            throw new IllegalStateException("其他出库单表头信息不存在！");
        }

        HashMap<String, Object> headerMap = new HashMap<>();
        headerMap.put("cgeneralhid", otherInBoundHeaderVo.getCgeneralhid());
        headerMap.put("vtrantypecode", otherInBoundHeaderVo.getVtrantypecode());
        return headerMap;
    }

    /**
     * 处理外部接口调用和库存更新
     *
     * @param cgeneralhid 表头主键
     * @param vBillCode   单据编号
     * @param loginUser   登录用户
     * @param detailSize  明细数量
     * @return 结果
     */
    private AjaxResult handleExternalApiAndInventory(String cgeneralhid, String vBillCode, LoginUser loginUser, int detailSize) throws IOException {
        // 调用外部接口
        NccApiResponse apiResponse = nccHttpUtils.post(AUDIT_API_URL, "[" + cgeneralhid + "]");

        // 校验NCC响应
        DataProcessCommonUtils.validateNccResponse(apiResponse);

        // 更新单据状态
        otherInboundOrderMapper.updateBillState(cgeneralhid, BillStatusConstant.SIGNED_CODE, loginUser.getUsername(), DataProcessUtils.getLocalDate(), null);

        // 更新库存管理
        Integer rowCount = inventoryManagerUtils.wmsWarehouseIn(vBillCode, "OtherWareHouseIn");
        if (rowCount != null && detailSize == rowCount) {
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vBillCode), DocumentType.OTHER_INBOUND.getCode(), "签字"));
        } else {
            otherInboundOrderMapper.updateBillState(cgeneralhid, BillStatusConstant.WMS_FAILURE_CODE, loginUser.getUsername(), DataProcessUtils.getLocalDate(), null);
            return AjaxResult.error(messageUtil.updateDocumentWmsFailureMessage(DocumentType.OTHER_INBOUND.getCode()));
        }
    }

    /**
     * 更新材料出库单
     *
     * @param headerMap  表头数据
     * @param detailList 明细列表
     * @param loginUser  登录用户
     * @return 更新结果
     */
    private AjaxResult updateOtherInOrder(HashMap<String, Object> headerMap, List<HashMap<String, Object>> detailList, LoginUser loginUser) {
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("ic_generalin_h", headerMap);
        resultMap.put("ic_generalin_b", detailList);

        return updateOtherInboundOrder(resultMap, loginUser, true);
    }

    /**
     * 其他入库单回退
     *
     * @param headerId  表头主键
     * @param loginUser 操作人
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult orderBack(String headerId, LoginUser loginUser) {
        HashMap<String, String> billStatusMap = otherInboundOrderMapper.getBillStatus(headerId);
        String billState = billStatusMap.get("billState");
        String vbillCode = billStatusMap.get("vbillcode");
        AjaxResult ajaxResult = messageUtil.cancelExtractBillMessage(billState, DocumentType.OTHER_INBOUND.getDescription());
        return ajaxResult.isSuccess() ? processOrderBack(headerId, loginUser, vbillCode) : ajaxResult;

    }

    private AjaxResult processOrderBack(String headerId, LoginUser loginUser, String vbillCode) {
        // 撤回其他入库单表头
        int i = otherInboundOrderMapper.orderBackHead(headerId, loginUser.getUserId().toString());
        if (i > 0) {
            // 撤回其他入库单表体
            int i1 = otherInboundOrderMapper.orderBackDetails(headerId, loginUser.getUserId().toString());
            if (i1 > 0) {
                return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillCode), DocumentType.OTHER_INBOUND.getCode(), "取消提取"));
            }
        }
        return AjaxResult.error("未知系统错误，请联系系统管理员处理！");
    }

    /**
     * 更新库存
     *
     * @param cgeneralhid 表头主键
     * @return 操作结果
     */
    @Override
    public AjaxResult updateInventory(String cgeneralhid, LoginUser loginUser) {
        try {
            // 获取单据表头
            OtherInBoundHeaderVo otherInBoundHeaderVo = otherInboundOrderMapper.selectOtherInboundOrderHeaderByBillCode(cgeneralhid);

            // 获取单据明细
            List<OtherInBoundBodyVo> details = otherInboundOrderMapper.getLocalOtherInBoundDetails(cgeneralhid, null);

            // 检查库存是否充足
//            checkInventory(details, otherInBoundHeaderVo);
            inventoryManagerUtils.verifyInventorySign(details, "warehousein", otherInBoundHeaderVo.getVtrantypecode(), DocumentType.OTHER_INBOUND.getCode());
            // 执行入库操作
            Integer rowCount = inventoryManagerUtils.wmsWarehouseIn(otherInBoundHeaderVo.getVbillcode(), "OtherWareHouseIn");

            // 更新单据状态
            updateBillState(cgeneralhid, loginUser, rowCount, details.size());
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(otherInBoundHeaderVo.getVbillcode()), DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), "签字"));
        } catch (InventoryException e) {
//            log.error("库存检查失败: {}", e.getMessage());
            return AjaxResult.error(e.getMessage());
        } catch (Exception e) {
//            log.error("更新库存失败: {}", e.getMessage());
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 检查库存是否充足
     *
     * @param details              明细信息
     * @param otherInBoundHeaderVo 表头信息
     * @throws InventoryException 库存异常
     */
    private void checkInventory(List<OtherInBoundBodyVo> details, OtherInBoundHeaderVo otherInBoundHeaderVo) throws InventoryException {
        for (OtherInBoundBodyVo detail : details) {
            if (detail.getNshouldnum() < 0) {
                int resultType = inventoryManagerUtils.isEnough(detail.getVbillcode(), otherInBoundHeaderVo.getVtrantypecode(), detail.getCmaterialvid().getPk(), detail.getVbatchcode(), detail.getNnum(), "2", detail.getCstateid(), "", "");
                if (resultType == InventoryCheck.NO_ENOUGH.ordinal()) {
                    throw new InventoryException(detail.getCmaterialvid().getName() + "库存可用量不足！");
                } else if (resultType == InventoryCheck.NOT_ALLOWED.ordinal()) {
                    throw new InventoryException(detail.getCmaterialvid().getName() + "当前商品不支持在此单据类型下使用！");
                }
            }
        }
    }

    /**
     * 更新单据状态
     *
     * @param cgeneralhid 单据主键
     * @param loginUser   登录用户
     * @param rowCount    入库数量
     * @param detailSize  明细数量
     */
    private void updateBillState(String cgeneralhid, LoginUser loginUser, Integer rowCount, int detailSize) {
        if (rowCount == null || detailSize == rowCount) {
            otherInboundOrderMapper.updateBillState(cgeneralhid, BillStatusConstant.SIGNED_CODE, loginUser.getUsername(), DataProcessUtils.getLocalDate(), null);
        } else {
            throw new RuntimeException(messageUtil.updateDocumentWmsFailureMessage(DocumentType.OTHER_INBOUND.getCode()));
        }
    }
}
